import {Application} from "mydog";
import {GameStatus, PlayerStatus} from "./constants";
import {Player} from "./player";
import {cmd} from "../../config/cmd";
import {changeConGameState, changeInfoGameState, GameType} from "../util/gameUtil";
import {I_gameMgr,GameMgr} from "./gameMgr";
import {getLogger, Logger} from "log4js";
import {assert} from "../util/util";

interface I_tableInfo {
    tableid:number;
    seatcount:number;
    gamestatus:GameStatus;
}

export class Table{
    private app: Application;
    //tableId 从1开始
    private tableId: number;
    private players?:Array<Player>;
    private gameSatus:GameStatus;
    private gameMgr:I_gameMgr;
    private seatCount:number;
    private log:Logger;
    constructor(app: Application, tableId: number) {
        this.app = app;
        this.tableId = tableId;
        this.log = getLogger(app.serverId+"-"+("000"+tableId).substr(-3))
        this.gameSatus=GameStatus.FREE;
        assert(this.app.serverInfo.seatCount,"seatCount is null");
        this.seatCount = this.app.serverInfo.seatCount;
        this.players = new Array<Player>(this.seatCount);
        this.gameMgr=new GameMgr();
        this.gameMgr.init(this,{playerCount:this.seatCount})
    }

    update(dt: number) {
        if(this.isGameProcessing()){
            this.gameMgr.update(dt);
        }
    }

    sendMsgToAll(cmd: number, msg: any = null) {
        var uidsid = [];
        for(var i=0;i<this.players.length;i++){
            if(this.players[i]){
                uidsid.push( { "uid": this.players[i].uid, "sid": this.players[i].sid })
            }
        }
        this.app.sendMsgByUidSid(cmd, msg, uidsid);
    }

    sendMsgToPlayer(cmd: number, msg: any = null,player:Player) {
        this.app.sendMsgByUidSid(cmd, msg, [ { "uid": player.uid, "sid": player.sid }]);
    }

    sendMsgToOthers(cmd: number, msg: any = null,player:Player) {
        var uidsid = [];
        for(var i=0;i<this.players.length;i++){
            if(this.players[i]!=null && this.players[i]!=player){
                uidsid.push( { "uid": this.players[i].uid, "sid": this.players[i].sid })
            }
        }
        this.app.sendMsgByUidSid(cmd, msg, uidsid);
    }

    getPlayerCount():number{
        let count = 0;
        for(var i=0;i<this.players.length;i++){
            if(this.players[i]!=null){
                count++;
            }
        }
        return count;
    }

    canEnter():boolean{
        return this.gameSatus == GameStatus.FREE && this.getPlayerCount()<this.seatCount;
    }

    isGameProcessing():boolean{
        return this.gameSatus == GameStatus.PROCESSING;
    }

    getTableId():number{
        return this.tableId
    }

    getTableLogger():Logger{
        return this.log
    }

    getPlayerById(uid:number):Player|null{
        for(var i=0;i<this.players.length;i++){
            if(this.players[i] && this.players[i].uid==uid){
                return this.players[i]
            }
        }
        return null;
    }

    getPlayerBySeat(seat:number){
        return this.players[seat]
    }

    //玩家进入桌子
    enter(player:Player):boolean{
        let freeSeat = null;
        for(let i=0;i<this.seatCount;i++){
            if(this.players[i]==null){
                freeSeat=i;
                break;
            }
        }
        if(freeSeat==null){
            return false;
        }
        player.tableid = this.tableId;
        player.seat = freeSeat;
        this.log.info("player enter uid=%d seat=%d",player.uid,player.seat);
        this.players[freeSeat] = player;
        // 1.将自己的信息广播给其他玩家
        this.sendMsgToOthers(cmd.onPlayerEnter,player.toJson(),player);
        //2.修改链接状态
        let gameState = { "gameSvr": this.app.serverId,"gameType":this.app.serverInfo.gameType, "tableId": this.tableId };
        changeInfoGameState(player.uid, gameState);
        changeConGameState(player.uid, player.sid, gameState);
        return true;
    }

    /**
     * 准备好游戏场景进入房间
     * @param uid
     */
    enterTable(uid:number){
        let player = this.getPlayerById(uid);
        if(player == null){
            return false;
        }
        let tableInfo:I_tableInfo = {
            gamestatus: this.gameSatus,
            seatcount: this.seatCount,
            tableid: this.tableId
        }
        // 0.发送桌子信息
        this.sendMsgToPlayer(cmd.onTableInfo,tableInfo,player);
        // 1.先接收自己的消息
        this.sendMsgToPlayer(cmd.onPlayerEnter,player.toJson(),player);
        // 2.将其他玩家的信息发给自己
        for(var i=0;i<this.players.length;i++){
            if(this.players[i]!=null && this.players[i]!=player){
                this.sendMsgToPlayer(cmd.onPlayerEnter,this.players[i].toJson(),player)
            }
        }
        //3.通知游戏玩家进入桌子,处理断线重连
        this.gameMgr.onEnterTable(player);
    }

    ready(uid:number){
        if(this.isGameProcessing()){
            return false
        }
        let player = this.getPlayerById(uid);
        if(player == null){
            return false;
        }
        player.setStatus(PlayerStatus.READY);
        this.sendMsgToAll(cmd.onPlayerStatus,{uid:player.uid,seat:player.seat,status:player.status})
        if(this.gameMgr.canGameStart()){
            this.onGameStart();
        }
    }

    unReady(uid:number){
        if(this.isGameProcessing()){
            return false
        }
        let player = this.getPlayerById(uid);
        if(player == null){
            return false;
        }
        player.setStatus(PlayerStatus.SITTING_UNREADY);
        this.sendMsgToAll(cmd.onPlayerStatus,{uid:player.uid,seat:player.seat,status:player.status})
    }

    leave(uid:number){
        let player = this.getPlayerById(uid);
        if(player == null){
            return false;
        }
        this.log.info("player leave uid=%d seat=%d",player.uid,player.seat);
        if(this.isGameProcessing()){
            //游戏开始时断线
            player.setStatus(PlayerStatus.DISCONNECTED);
            this.sendMsgToOthers(cmd.onPlayerStatus,{uid:player.uid,seat:player.seat,status:player.status},player)
        }else{
            //游戏未开始时踢出
            this.players[player.seat] = null;
            this.sendMsgToAll(cmd.onPlayerLeave,{uid:player.uid})
            //更新服务状态
            let gameState = { "gameSvr": "","gameType":GameType.NULL, "tableId": 0 };
            changeInfoGameState(uid, gameState);
            changeConGameState(uid, player.sid, gameState);
        }
    }

    relink(info: { "uid": number, "sid": string }){
        let player = this.getPlayerById(info.uid);
        if (player == null) {
            return false;
        }
        player.sid = info.sid;
        player.setStatus(PlayerStatus.PLAYING);
        //通知其他玩家更新自己状态
        this.sendMsgToOthers(cmd.onPlayerStatus,{uid:player.uid,seat:player.seat,status:player.status},player)
        return true;
    }

    onGameMsg(uid:number,msg: { event: string; data: any }){
        let  player = this.getPlayerById(uid);
        if(!player){
            return;
        }
        this.gameMgr.onReceiveMessage(player,msg);
    }

    getAllPlayer():Player[]{
        return this.players;
    }

    //游戏开始
    onGameStart(){
        this.log.info("onGameStart",this.players);
        this.gameSatus = GameStatus.PROCESSING;
        this.sendMsgToAll(cmd.onTableStatus,{gamestatus:this.gameSatus})
        for(let i=0;i<this.players.length;i++){
            if(this.players[i]!=null){
                this.players[i].setStatus(PlayerStatus.PLAYING);
            }
        }
        this.gameMgr.onGameStart()
    }

    //游戏结束
    onGameOver(){
        this.log.info("onGameOver")
        this.gameSatus = GameStatus.FREE;
        for(let i=0;i<this.players.length;i++){
            if(this.players[i]==null){
                continue;
            }
            if(this.players[i].isDisconnected()){
                // 踢出断线玩家
                this.leave(this.players[i].uid);
            }else{
                this.players[i].setStatus(PlayerStatus.SITTING_UNREADY);
                this.sendMsgToAll(cmd.onPlayerStatus,{uid:this.players[i].uid,seat:this.players[i].seat,status:this.players[i].status})
            }
        }
        this.sendMsgToAll(cmd.onTableStatus,{gamestatus:this.gameSatus})
    }
}